import { Field } from '@ngx-formly/core';
import { _ } from '@ag-grid-community/core';
import { isDate } from 'date-fns';

/**
 *  domain 数据填充
 */
// 对传入的域进行处理
export function fillField(domain: any, formState, searchFlag: boolean = false, searchText: string = '') {
  let result;
  if (type(domain) === 'object') {
    result = {};
  } else {
    result = [];
  }
  for (const key in domain) {
    let value = domain[key];
    const t = type(value);
    if (t === 'object') {
      value = fillField(value, formState, searchFlag, searchText);
    } else if (t === 'array') {
      value = [...fillField(value, formState, searchFlag, searchText)];
    } else {
      if (t === 'string') {
        const text = getText(value);
        if (text) {
          if (text === 'value') {
            if (searchFlag) return;
            value = searchText;
          } else {
            value = getValueUsingField(formState, text, true);
          }
        }
      }
    }

    let val = value;
    if (type(value) === 'array') {
      if (type(val) === 'array') {
        // 对解析出的数据做出筛选
        val = val.filter((elem) => {
            if (elem == undefined) return false;
            if (isDate(elem)) return true;
            if (type(elem) === 'object') {
              if (elem.hasOwnProperty('value')) {
                return elem.value !== null && elem.value !== undefined; //&& elem.value !==''
              } else {
                if (elem !== undefined) return true;
              }
            }
            if (type(elem) === 'string') {
              if (elem !== '') return true;
            }
          },
        );


      }
      value = val;
    } else if (type(value) === 'object' && val != null && val['filters']) {
      if (val.filters.length === 0) {
        if (val.groups.length === 0) {
          val = [];
        } else {
          val.filters = val.groups;
          val.groups = [];
        }
      }
    }

    if (key === 'groups' && val[0] && val[0].length === 0) {
      result[key] = [];
    } else {
      result[key] = val;
    }
  }
  // console.log(result);
  return result;
}

/**
 * 功能：表单字段回填
 * @param {Field} field
 * @param context
 */
export function backField(field: Field, context: any) {
  if (missing(context) || missing(field)) return;
  context = getO(context);
  if (context instanceof Object) {
    const fieldValue = field.formControl.value;
    for (let key in context) {
      let text = getText(context[key]);
      const m = {};
      m[key] = fieldValue != null ? missing(text) ? context[key] : getValueUsingField(fieldValue, text, true) : '';
      field.form.patchValue(m);
    }
  }
}

/**
 * 功能：插值表达式计算
 * @param {string} data
 * @returns {string}
 */
export function getText(data: string): string {
  let pattern = '(\\{\\{)(.+?)(\\}\\})';
  let regx = new RegExp(pattern);
  let a = regx.exec(data);
  if (a && a.length > 2) {
    return a[2];
  }
}


/**
 * 功能：字符串替换
 * @param context
 * @param {string} searchValue
 * @param {string} replaceValue
 */
export function replaceAll(context: string, searchValue: string, replaceValue: string) {
  if (exists(context) && type(context) === 'string') {
    return context.replace(new RegExp(searchValue, 'gm'), replaceValue);
  }
}

export function getO(value: any) {
  if (missing(value)) return {};
  value = replaceAll(value, '\"', '"');
  let context = replaceAll(value, '\'', '"');
  if (missing(context)) return;
  try {
    return JSON.parse(context);
  } catch (e) {
    console.error(context);
  }

}

export function getJson(value: any): string {
  return JSON.stringify(value);
}

/**
 * 功能：对象深度拷贝
 * @param data
 * @returns {any}
 */
export function deepClone(data) {
  var t = typeof (data), o, i, ni;

  if (data instanceof Array) {
    o = [];
  } else if (data instanceof Object) {
    if (data instanceof Date || data instanceof Function) {
      return data;
    }
    o = {};
  } else {
    return data;
  }

  if (data instanceof Array) {
    for (i = 0, ni = data.length; i < ni; i++) {
      o.push(deepClone(data[i]));
    }
    return o;
  } else if (data instanceof Object) {
    for (i in data) {
      o[i] = deepClone(data[i]);
    }
    return o;
  }
}

/**
 * 功能：深度比较两个对象
 * @param x
 * @param y
 * @returns {boolean}
 */
export function deepCompare(x, y) {
  var i, l, leftChain, rightChain;

  function compare2Objects(x, y) {
    let p;

    // remember that NaN === NaN returns false
    // and isNaN(undefined) returns true
    if (isNaN(x) && isNaN(y) && typeof x === 'number' && typeof y === 'number') {
      return true;
    }

    // Compare primitives and functions.
    // Check if both arguments link to the same object.
    // Especially useful on the step where we compare prototypes
    if (x === y) {
      return true;
    }

    // Works in case when functions are created in constructor.
    // Comparing dates is a common scenario. Another built-ins?
    // We can even handle functions passed across iframes
    if ((typeof x === 'function' && typeof y === 'function') ||
      (x instanceof Date && y instanceof Date) ||
      (x instanceof RegExp && y instanceof RegExp) ||
      (x instanceof String && y instanceof String) ||
      (x instanceof Number && y instanceof Number)) {
      return x.toString() === y.toString();
    }

    // At last checking prototypes as good as we can
    if (!(x instanceof Object && y instanceof Object)) {
      return false;
    }

    if (x.isPrototypeOf(y) || y.isPrototypeOf(x)) {
      return false;
    }

    if (x.constructor !== y.constructor) {
      return false;
    }

    if (x.prototype !== y.prototype) {
      return false;
    }

    // Check for infinitive linking loops
    if (leftChain.indexOf(x) > -1 || rightChain.indexOf(y) > -1) {
      return false;
    }

    // Quick checking of one object being a subset of another.
    // todo: cache the structure of arguments[0] for performance
    for (p in y) {
      if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) {
        return false;
      } else if (typeof y[p] !== typeof x[p]) {
        return false;
      }
    }

    for (p in x) {
      if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) {
        return false;
      } else if (typeof y[p] !== typeof x[p]) {
        return false;
      }

      switch (typeof (x[p])) {
        case 'object':
        case 'function':

          leftChain.push(x);
          rightChain.push(y);

          if (!compare2Objects(x[p], y[p])) {
            return false;
          }

          leftChain.pop();
          rightChain.pop();
          break;

        default:
          if (x[p] !== y[p]) {
            return false;
          }
          break;
      }
    }

    return true;
  }

  if (arguments.length < 1) {
    return true; //Die silently? Don't know how to handle such case, please help...
    // throw "Need two or more arguments to compare";
  }

  for (i = 1, l = arguments.length; i < l; i++) {

    leftChain = []; //Todo: this can be cached
    rightChain = [];

    if (!compare2Objects(arguments[0], arguments[i])) {
      return false;
    }
  }
  return true;
}

/**
 * 对象拷贝，参考$.extend()实现。首个参数为true时为深度拷贝，默认为false。
 *
 * 深度遍历，使用方法：
 *    let newObj = this.extend(true, {}, objA, objB);
 *
 * @param {any} args
 * @returns
 */
export function extend(...args) {

  let options, name, src, srcType, copy, copyType, copyIsArray, clone,
    target = args[0] || {},
    i = 1,
    length = args.length,
    deep = false;

  if (typeof target === 'boolean') {
    deep = target;
    target = args[i] || {};
    i++;
  }
  if (typeof target !== 'object' && typeof target !== 'function') {
    target = {};
  }
  if (i === length) {
    target = this;
    i--;
  }
  for (; i < length; i++) {
    if ((options = args[i]) !== null) {
      for (name in options) {
        src = target[name];
        copy = options[name];
        // 若参数中字段的值就是目标参数，停止赋值，进行下一个字段的赋值
        // 这是为了防止无限的循环嵌套
        if (target === copy) {
          continue;
        }
        srcType = isArray(src) ? 'array' : typeof src;
        // 不能用typeof判断一个数组是否为数组格式，例：typeof [] -> object。如需判断的话可用'[] instanceof Array'方法。
        // copyType = typeof copy;
        if (deep && copy && ((copyIsArray = isArray(copy)) || typeof copy === 'object')) {
          if (copyIsArray) {
            copyIsArray = false;
            clone = src && srcType === 'array' ? src : [];
          } else {
            clone = src && srcType === 'object' ? src : {};
          }
          target[name] = extend(deep, clone, copy);
        } else if (copy !== undefined) {
          target[name] = copy;
        }
      }
    }
  }
  return target;

  function isArray(obj: object) {
    return Array.isArray(obj) || type(obj) === 'array';
  }

  function type(obj: object) {
    if (obj === null) {
      return obj + '';
    }
    return typeof obj === 'object' || typeof obj === 'function' ? 'object' : typeof obj;
  }
}

/**
 * 功能：数据类型检查
 * @param data
 * @returns {string}
 */
export function type(data: any): string {
  let result: string;
  let t = Object.prototype.toString.call(data);
  switch (t) {
    case '[object Number]':
      result = 'number';
      break;
    case '[object String]':
      result = 'string';
      break;
    case '[object Boolean]':
      result = 'boolean';
      break;
    case '[object Date]':
      result = 'date';
      break;
    case '[object Array]':
      result = 'array';
      break;
    case '[object Object]':
      result = 'object';
      break;
    case '[object File]':
      result = 'file';
      break;
    default:
      result = typeof data;
      break;
  }
  return result;
}

/**
 * 功能：判断对象是否不存在
 * @param value
 * @returns {boolean}
 */
export function missing(value: any): boolean {
  return _.missing(value);
}

export function missingOrEmpty(value: any[] | string): boolean {
  return _.missingOrEmpty(value);
}

export function missingOrEmptyObject(value: any): boolean {
  return _.missingOrEmptyObject(value);
}

/**
 * 功能：判断对象是否存在
 * @param value
 * @returns {boolean}
 */
export function exists(value: any): boolean {
  return _.exists(value);
}

export function existsObject(value: any): boolean {
  return _.missingOrEmptyObject(value);
}

/**
 * 功能：获取对象中的指定field值，支持多级（点号）
 * @param data
 * @param {string} field
 * @param {boolean} fieldContainsDots
 * @returns {any}
 */
export function getValueUsingField(data: any, field: string, fieldContainsDots: boolean): any {
  return _.getValueUsingField(data, field, fieldContainsDots);
}

/**
 * 功能：表达式计算（基于当前上下文）
 * @param ctx
 * @param {string | boolean} expression
 * @returns {any}
 */
// export function evalExpression(ctx: any, expression: string | boolean) {
//     if (typeof expression === 'string') {
//         let e = "`${" + expression + "}`";
//         let value = eval(e);
//         if (value == 'true' || value == 'false') {
//             return getO(value);
//         }
//         return value;
//     } else {
//         return expression ? true : false;
//     }
// }

export function isDefined(value: any) {
  return value !== null && value !== undefined;
}

export function isObject(value: any) {
  return isDefined(value) && typeof value === 'object';
}

export function isPromise(value: any) {
  return value instanceof Promise;
}

export function isFunction(value: any) {
  return value instanceof Function;
}

// /**
//  * 功能：获取指定的订阅主题
//  */
// export function getSubject(ctx: any, key: string): Subject<any> {
//   let subject = ctx.subjects[key];
//   if (missing(subject)) {
//     subject = new Subject();
//     ctx.subjects[key] = subject;
//   }
//   return subject;
// }


/**
 * 格式画字符串
 * @param fmt 格式化的字符串 'yyyy-MM-dd HH:mm:ss' or 'yyyy-MM-dd'
 * @param date  传入的日期
 * @returns {any}
 */
export function dateFormat(fmt: string, date: Date) {
  let o = {
    'M+': date.getMonth() + 1,                 //月份
    'd+': date.getDate(),                    //日
    'H+': date.getHours(),                   //小时
    'm+': date.getMinutes(),                 //分
    's+': date.getSeconds(),                 //秒
    'q+': Math.floor((date.getMonth() + 3) / 3), //季度
    'S': date.getMilliseconds(),             //毫秒
  };
  if (/(y+)/.test(fmt))
    fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length));
  for (let k in o)
    if (new RegExp('(' + k + ')').test(fmt))
      fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length)));
  return fmt;
}

/*数字转千分位*/
export function formatNumber(value, fixed) {
  if (value == null || value == undefined || value == '') value = 0;
  let n = parseFloat(value).toFixed(fixed);

  let re = /(\d{1,3})(?=(\d{3})+(?:\.))/g;

  return n.replace(re, '$1,');
}

/*ag-grid格式化数字*/
export function agCurrency(data) {
  let iFixed = 2;
  if (data.colDef.hasOwnProperty('fixed')) {
    iFixed = Number(data.colDef.fixed);
  }
  if (data.value == undefined) {
    return '￥' + formatNumber(0, iFixed);
  } else
    return '￥' + formatNumber(data.value, iFixed);
}

export function agNumber(data) {
  let iFixed = 2;
  if (data.colDef && data.colDef.hasOwnProperty('fixed')) {
    iFixed = Number(data.colDef.fixed);
  }
  return formatNumber(data.value, iFixed);
}

/**科学计数法转化为数值字符串形式**/
export function toNonExponential(num) {
  if (num === null || num === undefined) return num;
  if (type(num) !== 'number') return num;
  let m = num.toExponential().match(/\d(?:\.(\d*))?e([+-]\d+)/);
  return num.toFixed(Math.max(0, (m[1] || '').length - m[2]));
}




